from contextlib import contextmanager
from decimal import Decimal, ROUND_DOWN, ROUND_HALF_UP
from typing import Optional


def is_num(string: str) -> bool:
    if isinstance(string, (int, float)):
        return True
    try:
        float(string)
        return True
    except (TypeError, ValueError):
        return False


@contextmanager
def acquire_timeout(lock, timeout):
    result = lock.acquire(timeout=timeout)
    try:
        yield result
    finally:
        if result:
            lock.release()


def try_parse_int(num) -> Optional[int]:
    try:
        return int(num)
    except (TypeError, ValueError):
        return None


def str2float(string, default=None):
    try:
        return float(string)
    except (TypeError, ValueError):
        return default


def format_num(num, unit):
    num = Decimal(str(num))
    unit = Decimal(str(unit))
    return float((num / unit).quantize(Decimal('1.'), rounding=ROUND_HALF_UP) * unit)
